perm filename MIXBUG[MIX,SYS] blob
sn#020793 filedate 1972-02-29 generic text, type T, neo UTF8
COMMENT ⊗ VALID 00026 PAGES
RECORD PAGE DESCRIPTION
00001 00001
00005 00002 BEGIN MIXBUG
00009 00003 comment INCHAR is a subroutine to read one char from the TTY and
00010 00004 comment SCAN is a subroutine to return one input token. the token
00013 00005 opdef scan [pushj p, .]
00017 00006 comment EXPR is a subroutine to read in and evaluate an expression.
00023 00007 comment WVAL is a subroutine to read in and evaluate a w-value.
00026 00008 comment FPOINT is a table of byte pointers for depositing things
00027 00009 comment INST is a subroutine to read an instruction.
00031 00010 comment ADDR is a subroutine to read an expression and see whether
00033 00011 comment GETSYM is a subroutine to find a symbolic expression for
00036 00012 comment these are a couple of subroutines to do some outputting:
00038 00013 comment MIXBUG is the starting address of the command interpreter.
00040 00014 comment EXAMIN is what looks at core locations and displays what it sees.
00042 00015 esi: addr get the address
00050 00016 eb: addr get address
00052 00017 es: addr get address
00054 00018 en: addr get address
00055 00019 comment DPOSIT is where we make deposits.
00056 00020 di: addrc get address followed by ←
00057 00021 comment BREAK and UBREAK are the places which handle
00060 00022 comment JUMPER is (would you believe) what does the jumping
00061 00023 comment XXXX is where we go to execute a particular instruction
00062 00024 comment EQUAL is used to show things in different styles
00063 00025 comment LF is where we display the next location
00064 00026 BEND MIXBUG
00065 ENDMK
⊗;
BEGIN MIXBUG
COMMENT ⊗ MIXBUG is the dynamic debugger that goes with MIX. It is essentially
a few more buttons. Each of these buttons has <alt-mode> as
the first character of its name. The buttons are as follows:
$B address This sets a breakpoint at address.
$U address This removes the breakpoint at address
$U This removes all breakpoints
$E address This examines and dipslays the contents of address
in symbolic instruction mode.
$ES address This examines the contents of address in symbolic decimal mode.
$EB address This examines the contents of address in byte mode.
$EA address This examines the contents of address in ALF mode
$ED address This examines the contents of address in decimal mode
$EN address This examines the contents of address in numeric-instruction mode.
$=S address This evaluates the address and types it (the address itself) in symbolic form.
$=D address This evaluates the address and types it in decimal form.
$DW address← w-value This deposits this w-value in this address
$DI address← instruction This deposits this instruction in this address.
$J address This begins execution at this address
$X instruction This causes this instruction to be executed.
$<line-feed> This causes *+1 to be displayed in the same mode as *
Note: all addresses, instructions, w-values may be
symbolic, using the symbols of the most recently
loaded .MLD file. The special character *
when not used as a multiply operator, means
the address of the currently open location,
if there is one, and the value of the P.C.
if there is no currently open location.
⊗
tac1←1
tac2←2
tac3←3
tac4←4
tac5←5
tac6←6
tac7←7
value←10
v1←11
scant←12
scnval←13
char←14
spec←←15
spec2←←16
↑acsave: block 17 ; for saving the ac's
numsym: 0 ; 0 if still possibly a number
seqnam: 0 ; will hold the sequence name at various times
0
origin: -1 ; will hold the value of *
comment ⊗ INCHAR is a subroutine to read one char from the TTY and
convert it to sixbit. the char is returned in the acc. CHAR.
if a <c-r> is read, the following <l-f> is also read and
returned as octal 100.
⊗
opdef inchar [pushj p, .]
inchr0: inchwl char ; read a char
jumpe char, .-1 ; ignore <null>
cain char, 11 ; convert <tab>
movei char, " " ; to <space>
cain char, 15 ; ignore <c-r>
jrst inchr0
cain char, 12 ; convert <l-f>
jrst [movei char, 100 ; to octal 100
popj p,] ; and return
trze char, 100 ; convert other chars to sixbit
troa char, 40
trz char, 40
popj p, ; return
comment ⊗ SCAN is a subroutine to return one input token. the token
is returned in SCANT, its associated value (if it has one)
is returned in SCNVAL, and the first char of the next token
is in CHAR.
the permissable tokens are given below:
⊗
LINE←0 ; end of line
COMMA←1 ; comma
LPAREN←2 ; left-parenthesis
RPAREN←3 ; right-parenthesis
SYM←4 ; identifier or number (associated value is the MIX word for the right thing)
PLUS←5 ; plus
MINUS←6 ; minus
STAR←7 ; asterisk (associated value is value of ORIGIN)
SLASH←10 ; slash
DOWNAR←11 ; double slash
COLON←12 ; colon
WHAT←13 ; identifier not found in symbol table
LEFTAR←14 ; left arrow
SPACE←15 ; space or other delimiter
comment ⊗ CHRTAB gives information about the various input chars:
CHRTAB+i= 0 if it is an illegal character
k if k is the token number for it and it isn't special
bits ∨ k if k is the sixbit for the token and bits are special bits:
bit 0 → a letter or a digit
bit 1 → a letter
bit 2 → a LINE or a SLASH
⊗
ULIST1
CHRTAB: for i ← 0,100
{ULIST2
j←←0
ife i-100, {j←← 1b2 ∨ line}
ife i-' ', {j←← space}
ife i-',', {j←← comma}
ife i-'(', {j←← lparen}
ife i-')', {j←← rparen}
ife i-'+', {j←← plus}
ife i-'-', {j←← minus}
ife i-'*', {j←← star}
ife i-':', {j←← colon}
ife i-'←', {j←← leftar}
ife i-'/', {j←← 1b2 ∨ slash}
ifge i-'A', {ifle i-'Z', {j←← 3b1 ∨ i-20}}
ifge i-'0', {ifle i-'9', {j←← 1b0 ∨ i-20}}
j
}
LIST
opdef scan [pushj p, .]
scan00: jumpn char, .+3 ; wait for non-blank character
inchar
jrst .-2
move scnval, origin ; default value of scnval is ORIGIN
skipn scant, chrtab(char) ; check table
jrst bugerr ; illegal character
tlnn scant, 700000 ; are any of the special bits on
jrst [inchar ; no → put next char in CHAR
popj p,] ; and return
tlze scant, 100000 ; is it LINE or SLASH?
jrst [caie scant, slash ; yes, is it slash?
popj p, ; no → it's line, so return
inchar ; get next char
caie char, '/' ; is next char a slash?
popj p, ; no → return
inchar ; yes → get next char
movei scant, downar ; and compress two slashes into downar
popj p,] ; and finally, return
move tac1, [point 6, seqnam] ; pointer to sequence name
setzm seqnam ; set sequence name to blanks
setzm seqnam+1
movei tac2, =12 ; maximum of 12 chars
setzb scnval, numsym ; scnval starts as zero, numsym shows number
scan1: tlze scant, 200000 ; is it a letter
setom numsym ; yes → we don't have a number
tlz scant, 400000 ; turn off letter-digit bit
sosl tac2 ; one more char in seqnam
idpb char, tac1 ; so put it there
imuli scnval, =10 ; no fix up scnval if number
add scnval, scant
inchar ; get next char
skipn scant, chrtab(char) ; and look at table
jrst bugerr ; illegal character
jumpl scant, scan1 ; if it's a digit or letter, keep the sequence going
movei scant, sym ; not a digit or letter, so we have whole sequence
skipn numsym ; was it a number?
popj p, ; yes → return with right token and value
ldb tac1, [point 8, seqnam, 7] ; hash into symbol table
ldb tac2, [point 8, seqnam, 15] ; by taking first two groups of 8 bits
xor tac1, tac2 ; and XORing them
addi tac1, symtab ; this gives us the actual pointer
skipa ; for the first time through
scan2: hrrz tac1, (tac1) ; get base address of next entry
jumpe tac1, [movei scant, what ; zero → this symbol is not in the table
popj p, ] ; return with bad news
move tac2, seqnam ; see if this entry is it
came tac2, (tac1) 1 ; do first six chars match?
jrst scan2 ; no → try next entry
move tac2, seqnam+1 ; now try next six chars
came tac2, (tac1) 2 ; do they match?
jrst scan2 ; no → try next entry
move scnval, (tac1) 3 ; yes → this is it so get associated MIX word
scan3: movei scant, sym ; it's a symbol
popj p, ; return
comment ⊗ EXPR is a subroutine to read in and evaluate an expression.
it assumes that the first char of the first token is in CHAR.
it skips on return if a valid expression was found--VALUE
contains the MIX word generated by the expression.
it doesn't skip if a valid expression was not found.
in either case, the next token is in SCANT.
⊗
opdef expr [pushj p, .]
expr00: setzb value, spec ; we initialize value to zero
scan ; get first token
caie scant, sym ; if it is a symbol
cain scant, what ; or a what
jrst expreg ; see if it is a register
expr01: caie scant, sym ; if it is SYM
cain scant, star ; or *
jrst [move value, scnval ; we start off
jrst expr2]
caie scant, plus ; if it is +
cain scant, minus ; of -
jrst expr1 ; yes → we have a unary-operator
aos (p) ; otherwise it is a valid exprssion (empty)!!
popj p, ; so skip on return
expr1: move tac3, scant ; save operator
scan ; get next token
cain scant, sym ; is it a symbol
jrst .+3 ; yes → we're OK
caie scant, star ; or a *
popj p, ; no → error
cain tac3, minus ; was operator a minus sign?
tlc scnval, 400000 ; yes → complement sign bit of MIX word
move value, scnval ; value is now what we want it to be
expr2: scan ; get next token
cail scant, plus ; is it a binary-operator
caile scant, colon
jrst [aos (p) ; no → we have found our expression
popj p, ] ; so skip on return
move tac3, scant ; remember what the operator is
expr3: scan ; get next token
cain scant, sym ; is it a symbol
jrst .+3 ; yes → we're OK
caie scant, star ; or *
popj p, ; no → error return
move tac4, value ; save original value
tlze value, 400000 ; convert value to two's complement
movns value
tlze scnval, 400000 ; convert scnval to two's complement
movns scnval
xct binop-plus(tac3) ; do whatever the operation calls for
jumpg value, expr2 ; value>0 → it's already in MIX format
jumpe value, [tlne tac4, 400000 ; value=0 → must check sign of first operand
tlo value, 400000 ; first operand < 0 → new value should be also
jrst expr2] ; now we have MIX format
movns value ; value<0 → take negative
tlo value, 400000 ; and turn on sign bit
jrst expr2 ; and go back for next operator
binop: add value, scnval ; PLUS → we add the operands
sub value, scnval ; MINUS → we subtract the operands
imul value, scnval ; STAR → we multiply the operands
idiv value, scnval ; SLASH → we divide the operands
pushj p, [setz value+1 ; DOWNAR → special divide
ashc value, -5
div value, scnval
popj p,]
pushj p, [imuli value, =8 ; COLON → usually for fields
add value, scnval
popj p,]
expreg: move tac2, seqnam ; see if it is a register
movei tac1, reglst
camn tac2, (tac1) ; is it this one?
jrst [move value, regnum-reglst(tac1) ; yes ← get address relative to mc0000
setom spec ; so we remember that it is a register
scan ; next token must be in scant
popj p,] ; error return
caige tac1, regnum-1 ; was that the last register to consider
aoja tac1, .-3 ; no
jrst expr01 ; yes → it wasn't a register
reglst: sixbit /ra/
sixbit /r1/
sixbit /r2/
sixbit /r3/
sixbit /r4/
sixbit /r5/
sixbit /r6/
sixbit /rx/
sixbit /rj/
regnum: acsave-mc0000+ra ; give addresses in acsave relative to mc0000
acsave-mc0000+r1
acsave-mc0000+r2
acsave-mc0000+r3
acsave-mc0000+r4
acsave-mc0000+r5
acsave-mc0000+r6
acsave-mc0000+rx
acsave-mc0000+rj
comment ⊗ WVAL is a subroutine to read in and evaluate a w-value.
it assumes that the first char of the first token is in CHAR.
it skips on return if a valid w-value was found--VALUE
contains the MIX word generated by the w-value.
it doesn't skip if a valid w-value was not found.
in either case, the next token is in SCANT.
⊗
opdef wval [pushj p, .]
wval00: setz tac7, ; tac7 will hold w-value while it is being generated
wval1: movei tac6, 5 ; tac6 will hold the f-part
expr ; get an expression
jrst [aos (p) ; couldn't → we're all done with w-value
move value, tac7 ; put proper thing into value
popj p,]
move tac5, value ; save value of expression
cain scant, lparen ; is it a left-paren?
jrst wval3 ; yes → go get f-part
wval2: caile tac6, 5 ; does f-part include sign bit?
jrst .+4 ; no
skipge tac5 ; yes → test sign of operand
tloa tac7, 400000 ; and use it
tlz tac7, 400000
dpb tac5, fpoint(tac6) ; now get other bytes
cain scant, comma ; comma?
jrst wval1 ; yes → back for next part
aos (p) ; neither → we're all done
move value, tac7 ; put proper thing into value
popj p, ; so skip on return
wval3: expr ; get expression for f-part
popj p, ; couldn't → error in w-value
move tac6, value ; need to remember value of f-part
caie scant, rparen ; is it right-paren?
popj p, ; no → error in w-value
skipl tac6 ; is it a valid f-part?
caile tac6, 55 ; first test: is it in the right range?
popj p, ; no → error
skipn fpoint(tac6) ; is table entry zero?
popj p, ; yes → error
scan ; get next token after )
jrst wval2 ; scan again
comment ⊗ FPOINT is a table of byte pointers for depositing things
into tac7. if an entry is zero, then it is not a valid f-part.
the sign byte is not included.
⊗
fpoint: 44b5
for y←1,5
{point y*6, tac7, y*6+5
}
repeat 2, {0}
for x←1,5
{for y←0,5
{ifge y-x, then {point (y-x+1)*6, tac7, y*6+5
}
ifl y-x, then {0
}
}
repeat 2, {0}
}
comment ⊗ INST is a subroutine to read an instruction.
the MIX word which is the instruction is returned in
VALUE. control is transferred to bugerr if a valid
instruction is not found.
⊗
opdef inst [pushj p, .]
inst00: scan ; get the first token
cain scant, sym ; is it a symbol?
jrst .+3 ; yes → it's OK
caie scant, what ; or an undefined symbol?
jrst bugerr ; no → error
skipe seqnam+1 ; second part of sequence name should be blanks
jrst bugerr ; but it's not
movei tac4, oplist ; no we will find op-code by a binary search
movei tac5, lastop ; tac4 and tac5 contain the lower and upper bounds
inst1: move tac1, tac5 ; get index
add tac1, tac4
lsh tac1, -1 ; divide by two to get average
move tac2, (1) ; get OP for comparison
sub tac2, seqnam
jumpg tac2, lower ; it is lower on the list
jumpl tac2, upper ; it is higher on the list
skipge tac7, gotop-oplist (tac1) ; is it a pseudo op?
jrst bugerr ; yes → error
jrst inst2 ; no → success!
lower: movni tac5, 1 ; reset upper limit
addb tac5, tac1 ; to index-1
caml tac5, tac4 ; lower>upper → error
jrst inst1
jrst bugerr
upper: movei tac4, 1 ; reset lower limit
addb tac4, tac1 ; to index+1
caml tac5, tac4 ; lower>upper → error
jrst inst1
jrst bugerr
inst2: expr ; get expression for address
jrst bugerr ; error
trz value, 770000 ; get rid of bad bits
hrl tac7, value ; put address into assembling MIX word
skipge value ; was sign bit on?
tlo tac7, 400000 ; yes → turn it on here, too
caie scant, comma ; is next token a comma?
jrst inst3 ; no → then we don't have an index field
expr ; get expression for the index field
jrst bugerr ; error
dpb value, [point 6, tac7, 23] ; put index field into MIX rd
inst3: caie scant, lparen ; is next token a left-parenthesis
jrst inst4 ; no → then we don't have a field-field
expr ; expression for field
jrst bugerr ; error
caie scant, rparen ; next token should be right-paren
jrst bugerr ; it ain't
dpb value, [point 6, tac7, 29] ; put field into MIX word
scan ; must get next token after )
inst4: jumpn scant, bugerr ; final token should be LINE
move value, tac7 ; this is the assembled instruction
popj p, ; so return
comment ⊗ ADDR is a subroutine to read an expression and see whether
it is a valid address.
it also checks to see that this is the last token in the line.
⊗
opdef addr [pushj p, .]
addr0: inchar ; input a char to start the expr
expr ; get the expression
jumpe spec, bugerr ; no expression → error
jumpn scant, bugerr ; next expression should be LINE
skipe spec ; did we get a register name?
popj p, ; yes → return right away
jumpl value, bugerr ; out of range → error
caile value, =3999
jrst bugerr
movem value, origin ; save address in ORIGIN
popj p, ; return
comment ⊗ ADDRC is a subroutine to read an expression and see whether
it is a valid address.
it also checks to see that it is followed by a left-arrow.
⊗
opdef addrc [pushj p, .]
addrc0: inchar ; input a char to start the expr
expr ; get the expression
jumpe spec, bugerr ; error
caie scant, leftar ; is next token a leftar?
jrst bugerr ; no → error
skipe spec ; did we get a register name
popj p, ; yes → return right away
jumpl value, bugerr ; out of range → error
caile value, =3999
jrst bugerr
movem value, origin ; save value of *
popj p, ; return
comment ⊗ GETSYM is a subroutine to find a symbolic expression for
a value. only symbols with equivalent MIX words between
0000 and 3999 are considered. GETSYM assumes that VALUE
contains the value to be considered. a pointer to the
best symbol table entry is returned in tac3 (zero if no
symbol was found) and the offset is returned in tac4.
⊗
opdef getsym [pushj p, .]
↑SYMGET: ;*RES* so I can call it from MIXDD
gets0: setz tac3, ; we obviously haven't found a symbol yet
movei tac4, =4000 ; and no symbol could have a worse offset than this
movei tac1, linked ; to start table search
gets1: skipn (tac1) 1 ; is there an entry?
JRST GETS3 ;*RES* no → search is over
skipl tac2, (tac1) 3 ; is equivalent value less than zero?
caile tac2, =3999 ; or greater than 3999?
jrst gets2 ; yes → not a valid symbol
sub tac2, value ; get difference between value and symbl's equivalent
movns tac2 ; take VALUE-SYMBOL
jumpl tac2, gets2 ; don't want a negative offset
caml tac2, tac4 ; is it better than we already have?
jrst gets2 ; no → then don't use it
move tac3, tac1 ; yes → then we should save it
move tac4, tac2
gets2: addi tac1, 4 ; now look at next entry
jrst gets1
GETS3: SKIPN TAC3 ;*RES* IF NO HIT,
MOVE TAC4,VALUE ;*RES* SET OFFSET TO VALUE
POPJ P,
comment ⊗ these are a couple of subroutines to do some outputting:
OUTDEC - output a space followed by the decimal number in VALUE
OUTNAM - output a space followed by the sequence name in VALUE,VALUE+1
⊗
opdef outdec [pushj p, .]
↑outd1: idivi value, =10 ; get digits from right end
hrlm value+1, (p) ; put them on the stack
skipe value ; was that the last digit?
pushj p, outd1 ; no → go back for more
hlrz value, (p) ; get digit off stack
addi value, 60 ; convert to ascii
outchr value ; output it
popj p, ; next digit or return
opdef outnam [pushj p, .]
outnm0: move tac4, [point 6, value] ; pointer to chars is in tac4
outnm1: ildb tac5, tac4 ; get a char
jumpe tac5, outnm2 ; blank → end of sequence
addi tac5, 40 ; convert to ascii
outchr tac5 ; output the char
came tac4, [point 6, value+1, 35] ; was that the 12th char?
jrst outnm1 ; no
outnm2: popj p, ; return
comment ⊗ MIXBUG is the starting address of the command interpreter.
⊗
↑mixbug:
movei p, acsave ; save all ac's except p
blt p, acsave+16
move p, [iowd 40, pdl] ; initialize push-down-pointer
skipge origin ; do we already have an address there?
jrst [hrrz tac1, acsave+pc ; no → then use value of p.c.
subi tac1, mc0000 ; relative to mc0000
movem tac1, origin
jrst .+1]
inchar ; input the first char
cain char, 'E' ; is it an E (sixbit)
jrst examin ; yes → go to examine
cain char, 'D' ; is it a D?
jrst dposit ; yes → go to dposit
cain char, 'B' ; is it a B?
jrst break ; yes
cain char, 'U' ; is it a U?
jrst ubreak ; yes
cain char, 'J' ; how about J?
jrst jumper ; yes
cain char, 'X' ; or X?
jrst xxxx ; yes
cain char, '=' ; =?
jrst equal ; yes
cain char, 100 ; line-feed?
jrst lf ; yes
; none of these → error
bugerr: outstr [asciz /???
/]
bugout: jumpe scant, .+3 ; wait for LINE
scan
jrst .-2
movsi p, acsave ; restore all ac's
blt p, 16
move p, [iowd 40, pdl] ; restore push-down-pointer
jrst button ; and return to button mode
comment ⊗ EXAMIN is what looks at core locations and displays what it sees.
⊗
examin: inchar ; get char to tell what kind of examine
setzm mode ; mode will help use remember what mode of display we're in
jumpe char, esi ; blank → symbolic instruction
aos mode
cain char, 's' ; S → symbolic decimal
jrst es
aos mode
cain char, 'b' ; B → byte
jrst eb
aos mode
cain char, 'a' ; A → alf
jrst ea
aos mode
cain char, 'd' ; D → decimal
jrst ed
aos mode
cain char, 'n' ; N → numeric instruction
jrst en
jrst bugerr ; none of these → error
mode: 0
modes: esi+1
es+1
eb+1
ea+1
ed+1
en+1
esi: addr ; get the address
outchr [" "]
move tac7, value ; tac7 will index to locatyon
PUSHJ P,DECIDF ;*RES* DECIDE WHETHER TO PRINT F
JRST ESI2 ;GO DO IT
COMMENT ⊗ The following routine is called to decide whether the F-field of
the instruction is to be printed. It is called by PUSHJ P,DECIDF,
with the relative instruction counter in register 7. On return, reg
10 contains the op code, reg 11 contains the field and reg 6 is a
flag: zero if field is to be printed, non-zero otherwise. As a nice
side effect, the op code mnemonic is an ASCIZ string at @STROP(10) on
exit.
⊗
↑DECIDF:
ldb value, [point 6, mc0000(tac7), 35] ; get op code
ldb value+1, [point 6, mc0000(tac7), 29] ; and f-field
setom tac6 ; tac6 will know whether we should output the field
hlrz tac2, strop(value) ;*RES* are there special names for different fields?
jumpe tac2, esi1 ; no
cain value, 5 ; is op special?
jrst [caile value+1, 3
setzb value+1, tac6
POPJ P,]
cain value, 6 ; or is it a shift?
jrst [caile value+1, =8
setzb value+1, tac6
POPJ P,]
cain value, =39 ; or is it a jump?
jrst [caile value+1, =12
setzb value+1, tac6
POPJ P,]
caige value, =40 ; or one of these jumps?
jrst esi1
caig value, =47
jrst [caile value+1, =8
setzb value+1, tac6
POPJ P,]
caig value, =55 ; or one of the modifies?
jrst [caile value+1, 4
setzb value+1, tac6
POPJ P,]
esi1: cain value, 0 ; is it a NOP?
jrst [caie value+1, 0
setz tac6,
POPJ P,]
cain value, 7 ; is it a MOVE?
jrst [caie value+1, 1
setz tac6,
POPJ P,]
cain value, =32 ; is it STJ?
jrst [caie value+1, 2
setz tac6,
POPJ P,]
caige value, =56 ; is it one which has (0:5) as standard field?
caig value, =33
jrst [caie value+1, 5
setz tac6,
POPJ P,]
skipe value+1 ;*RES* otherwise, it uses (0)
setz tac6,
POPJ P,
esi2: outstr @strop(value) ; output the op-code
outchr [" "] ; followed by a tab
hlrz value, mc0000(tac7) ; get address part
andi value, 7777 ; get good bits
skipge mc0000(tac7) ; is it negative?
tlo value, 400000 ; turn on sign bit
jumpge value, esi23
PUSHJ P,GETNSM ;*RES* FIND NEG SYMBOL
JRST ESI22 ;*RES* GO PRNT IT OUT
COMMENT ⊗ The following routine finds whether a negative address is in the
symbol table in either its negative form or absolute value. It is
called by PUSHJ P,GETNSM with the relative address reg 10. On return,
if there was a match in either case, register 3 contains the symbol
table address. If there was an exact match, reg 4 is non-zero.
Reg 11 is destroyed.
⊗
↑GETNSM:
hrrz value+1, value ; value+1 has absolute value
setzb tac3, tac4 ; we will search for a match
movei tac1, linked ; of value or |value|
esi21: skipn (tac1) 1 ; is there an entry?
POPJ P, ;*RES* no → end of table
camn value, (tac1) 3 ; is this a match?
jrst [move tac3, tac1 ; yes → we will use it
setom tac4 ; to remember it was exact
POPJ P,] ;*RES*
camn value+1, (tac1) 3 ; match of absolute value?
move tac3, tac1 ; yes → remember it
ADDI TAC1,4 ;*RES* POINT TO NEXT ENTRY
jrst esi21 ; and back to table
esi22: jumpn tac4, esi221 ; -1 → exact match
outchr ["-"] ; we will need this
jumpn tac3, esi221 ;*RES* tac3=0 → no suitable symbol found
HRRZ VALUE,VALUE ;*RES* GET ABSOLUTE VALUE
JRST ESI24 ;*RES* GO WRITE IT
esi221: move value, (tac3) 1 ; output the symbol
move value+1, (tac3) 2
outnam
jrst esi3 ; all done with address field
esi23: getsym ; get a matching symbol
jumpe tac3, esi24 ; no match
caile tac4, =100 ; maximum offset of 100
jrst esi24
move tac2, tac4 ; remember offset
move value, (tac3) 1 ; output name
move value+1, (tac3) 2
outnam
move value, tac2 ; now do the offset
jumpe value, esi3 ; zero → don't type it
outchr ["+"]
esi24: outdec ; this could be any of several values
esi3: ldb value, [point 6, mc0000(tac7), 23] ; get index field
jumpe value, esi4 ; zero → don't output it
outchr [","] ; comma first
getsym ; get a matching symbol
jumpn tac4, [outdec ; not an exact match, so don't use it
jrst esi4]
move value, (tac3) 1 ; output the symbol
move value+1, (tac3) 2
outnam
esi4: jumpn tac6, esi5 ; are we supposed to output the field-field?
outchr ["("] ; yes
ldb value, [point 6, mc0000(tac7), 29] ; get it
getsym ; get a matching symbol
jumpn tac4, [outdec ; not an exact match, so don't use it
jrst esi41]
move value, (tac3) 1 ; output the symbol
move value+1, (tac3) 2
outnam
esi41: outchr [")"]
esi5: jrst bugout
eb: addr ; get address
outchr [" "]
movei tac1, "+" ; assume positive
skipge tac2, mc0000(value) ; are we right?
movei tac1, "-" ; no
outchr tac1 ; output the sign
move tac1, [point 6, tac2, 5] ; pointer to bytes
eb1: ildb value, tac1 ; get byte
outchr [" "] ; output a space
outdec ; output the byte
tlne tac1, 770000 ; is it the last byte?
jrst eb1 ; no
jrst bugout ; yes
ea: addr ; get address
outchr [" "]
move tac2, mc0000(value) ; must save pointer
move tac1, [point 6, tac2, 5] ; pointer to chars
ea1: ildb value, tac1 ; get a char
move value, mixasc(value) ; convert to ascii
outchr value ; and output it
tlne tac1, 770000 ; is is the last char?
jrst ea1 ; no
jrst bugout ; yes
es: addr ; get address
outchr [" "]
move value, mc0000(value) ; get value to output
es0: getsym ; get symbolic expression for it
jumpe tac3, es1 ; tac3=0 → couldn't find a symbol
caile tac4, =100 ; maximum offset of 100
jrst es1
move tac1, tac4 ; save offset
move value, (tac3) 1 ; put sequence into value
move value+1, (tac3) 2 ; and value+1
outnam ; output the name
move value, tac1 ; now get the offset
jumpe value, es2 ; zero offset → don't print any
outchr ["+"]
es1: outdec ; either the offset or the entire value
es2: jrst bugout ; all done
ed: addr ; get address
outchr [" "]
move value, mc0000(value) ; get the value to output
ed0: movei tac1, "+" ; assume positive
jumpge value, .+3 ; right!
movei tac1, "-" ; wrong!!
tlz value, 400000 ; turn off sign bit
outchr tac1 ; output the sign
outdec ; and then the value
jrst bugout ; all done
en: addr ; get address
outchr [" "]
movei tac1, "+" ; assume positive
skipge tac2, mc0000(value) ; are we right?
movei tac1, "-" ; no
outchr tac1 ; output the sign
ldb value, [point 12, tac2, 17] ; get address field
outdec ; output it
move tac1, [point 6, tac2, 17] ; pointer to other fields
en1: ildb value, tac1 ; get field
outchr [" "]
outdec ; output it
tlne tac1, 770000 ; last field?
jrst en1 ; no
jrst bugout ; yes
comment ⊗ DPOSIT is where we make deposits.
⊗
dposit: inchar ; get next char
cain char, 'i' ; i?
jrst di ; deposit instruction
cain char, 'w' ; w?
jrst dw ; deposit w-value
jrst bugerr ; neither → error
di: addrc ; get address followed by ←
move spec2, value ; save address to deposit into
inst ; get instruction to put there
movem value, mc0000(spec2) ; so put it there
jrst bugout ; all done
dw: addrc ; get address followed by ←
move spec2, value ; save address to deposit into
wval ; get w-value to put there
jrst bugerr ; error
movem value, mc0000(spec2) ; so put it there
jrst bugout ; all done
comment ⊗ BREAK and UBREAK are the places which handle
Break and Unbreak commands
⊗
break: addr ; get address to set breakpoint
jumpl spec, bugerr ; don't allow register names for breakpoints
addi value, mc0000 ; make it an absolute address
movei tac1, =19 ; is it already in the table
camn value, bptab(tac1) ; is it this entry?
jrst bugout ; yes → don't put it in again
sojge tac1, .-2 ; check next entry
movei tac1, =19 ; now look for blank place
skipe bptab(tac1) ; is this entry zero?
sojge tac1, .-1 ; no → try next one
jumpl tac1, [outstr [asciz /too many breakpoints
/] ; tac1<0 → went all the way through table
jrst bugout]
movem value, bptab(tac1) ; now put this address into the table
jrst bugout ; and return
ubreak: inchar ; to check for line-feed
cain char, 100 ; is U followed by <l-f>>
jrst ubr1 ; yes → we delete all breakpoints
addr ; get address to unbreak
jumpl spec, bugerr ; don't allow register names for unbreaks
addi value, mc0000 ; make an absolute address
movei tac1, =19 ; find it in table
camn value, bptab(tac1) ; this entry?
jrst [setzm bptab(tac1) ; yes → make it zero
jrst bugout] ; and return
sojge tac1, .-2 ; no → try next
jrst bugout ; couldn't find it → so what
ubr1: movei tac1, =19 ; want to delete all entries
setzm bptab(tac1) ; so do it
sojge tac1, .-1
jrst bugout ; and return
↑bptab: repeat =20, {0⎇ ; this has the breakpoints
comment ⊗ JUMPER is (would you believe) what does the jumping
⊗
jumper: addr ; get address to jump to
jumpl spec, bugerr ; can't jump to a register name
addi value, mc0000 ; make it an absolute address
hrrm value, acsave+pc ; put it in right half of P.C.
movsi p, acsave ; now restore accumulators
blt p, 16
move p, [iowd 40, pdl] ; restore push-down-pointer
jrst mixmn1 ; and resume operations
comment ⊗ XXXX is where we go to execute a particular instruction
⊗
xxxx: inchar ; to start off inst
inst ; get the instruction
setzm jbusx ; in case it is JBUS *
movem value, acsave+instr ; to get set to go
movsi p, acsave ; now we must restore the accumulators
blt p, 16
move p, [iowd 40, pdl] ; restore push-down-pointer
tlo flags, siflag ; set single-instruction flag
jrst mixmn2 ; and begin execution
comment ⊗ EQUAL is used to show things in different styles
⊗
equal: inchar ; get descriptive character
cain char, 'd' ; decimal mode
jrst eqd ; yes
cain char, 's' ; symbolic mode
jrst eqs ; yes
jrst bugerr ; neither → error
eqd: addr ; get address to consider
jumpl spec, bugerr ; there are no equivalences for registers
outchr [" "]
jrst ed0 ; now go do it
eqs: addr ; get address to consider
jumpl spec, bugerr ; there are no equivalences for registers
outchr [" "]
jrst es0 ; now go do it
comment ⊗ LF is where we display the next location
⊗
lf: aos value, origin ; get next location
skipl tac1, mode ; now recall whatever mode we were in
caile tac1, 5 ; within allowable range?
jrst bugerr ; no → error
outchr [15] ; <c-r> to match the <l-f> we already have
outchr [" "]
jrst @modes(tac1) ; now go do it
BEND MIXBUG